﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Engine.Sgml.Validation {
    internal sealed class DoctypeValidator : IElementValidator {
        private SgmlDocument document;

        public DoctypeValidator(SgmlDocument document) {
            Guard.ArgumentNotNull(document, "document");
            this.document = document;
            }

        public SElement Validate(SElement element, SElement node) {
            // Узел документа должен находиться на уровне документа
            // Он не может повторяться более одного раза
            if (node.NodeType == SgmlNodeType.Document) {
                // Позиция узла должна соответствовать
                // первому узлу документа
                if (element.OrderIndex == 0 || (element.OrderIndex == 1 && node.FirstNode.IsXmlDeclaration()))
                    element.Parent = node;
                else {
                    // Если в начале документа существует
                    // узел о типе документа
                    if (HasDoctypeElement(node))
                        // Удалить узел о типе документа
                        node.Nodes.Pop();
                    else {
                        element.Parent = node;
                        // Переместить узел в начало документа
                        if (document.DocumentType == SgmlDocumentType.Xml && node.FirstNode.IsXmlDeclaration())
                            element.Move(1);
                        else
                            element.Move(0);
                        }
                    }
                }
            else {
                // Если узел существует на уровне документа
                SElement root = node.Root;
                if (HasDoctypeElement(root))
                    // Удалить узел о типе документа
                    node.Nodes.Pop();
                else if (document.DocumentType == SgmlDocumentType.Xml && root.FirstNode.IsXmlDeclaration())
                    //root.Nodes.Insert(element, 1);
                    root.FirstNode.AddAfterSelf(element);
                else
                    //root.Nodes.Insert(element, 0);
                    root.FirstNode.AddBeforeSelf(element);
                }
            return node;
            }

        private static bool IsDoctypeElement(SElement element) {
            return (element != null && element.NodeType == SgmlNodeType.DocumentType);
            }

        private static bool HasDoctypeElement(SElement element) {
            if (IsDoctypeElement(element.Nodes.GetOrDefault(0)))
                return true;
            if (IsDoctypeElement(element.Nodes.GetOrDefault(1)))
                return true;
            else
                return false;
            }
        }
    }
